<?php
// +-------------------------------------------------------------+
// | Tinysupe [ SIMPLE IS THE BEST ! ]
// +-------------------------------------------------------------+
// | Copyright (c) 2011 www.srccn.com All rights reserved.
// +-------------------------------------------------------------+
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +-------------------------------------------------------------+
// | Author: tinysu <tinysu@qq.com>
// +-------------------------------------------------------------+

/*****************************************************************
* Name:		SRCCN!Mailer/1.0
* 
* Useage:	header('Content-type:text/html; charset=utf-8');
*
*			$sm = new smailer($smtphost, $smtpport, true, $smtpuser, $smtppass);
*			$sm->logfile = 'smailer.log';
*			echo $sm->sendmail($mailto, $sender, $subject, $mailbody, $mailtype);
*
* Updated:	2012-03-23
******************************************************************/

class smailer
{
	public $debug, $logfile, $timeout;
	public $smtp_host, $smtp_port, $smtp_helo;
	public $smtp_auth, $smtp_user, $smtp_pass;
	
	private $smtp_sock;
	
	function __construct($smtp_host = '', $smtp_port = 25,$smtp_auth = false, $smtp_user, $smtp_pass){
		$this->debug = false;
		$this->logfile = '';
		$this->time_out = 30;
		$this->smtp_host = $smtp_host;
		$this->smtp_port = $smtp_port;
		$this->smtp_helo = 'localhost';
		$this->smtp_auth = $smtp_auth;
		$this->smtp_user = $smtp_user;
		$this->smtp_pass = $smtp_pass;
		$this->smtp_sock = false;
	}
	
	function __destruct(){
		
	}
	
	public static function validate($address) {
		$pregex = '/^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+';
		$pregex .= '@(?:(?:(?:[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!\.)){0,61}[a-zA-Z0-9_-]?\.)+[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!$)){0,61}[a-zA-Z0-9_]?)';
		$pregex .= '|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/';
		return preg_match($pregex, $address);
	}
  
	public function sendmail($mailto, $sender, $subject = '', $body = '', $mailtype, $mailcc = '', $mailbcc = '', $headers = ''){
		$from = $this->get_address($sender);
		$body = preg_replace('/(^|(\r\n))(\.)/is', '\1.\3', $body);
		
		$header = "MIME-Version:1.0\r\n";
		if (strtolower($mailtype) == 'html') {
			$header .= "Content-Type:text/html\r\n";
		}
		
		$header .= "To: $mailto\r\n";
		if ($mailcc != '') $header .= "Cc: $mailcc\r\n";

		$header .= "From: $sender\r\n";
		$header .= "Subject: $subject\r\n";
		$header .= $headers;
		$header .= "Date: ".date('r')."\r\n";
		$header .= "X-Mailer:By Smail (PHP/".phpversion().")\r\n";
		
		list($msec, $sec) = explode(' ', microtime());
		$header .= "Message-ID: ".date('YmdHis', $sec).'.'.($msec*1000000).'.'.$from.">\r\n";
		$mailto = explode(',', $this->get_address($mailto));
		
		if($mailcc != '') $mailto = array_merge($mailto, explode(',', $this->get_address($mailcc)));
		if($mailbcc != '') $mailto = array_merge($mailto, explode(',', $this->get_address($mailbcc)));
		
		$sent = true;
		foreach ($mailto as $rcpt_to) {
			if ($this->smtp_open($rcpt_to)) {
				if ($this->smtp_send($from, $rcpt_to, $header, $body)) {
					$this->log_write("E-mail has been sent to <".$rcpt_to.">\n");
				} else {
					$this->log_write("Error: Cannot send email to <".$rcpt_to.">\n");
					$sent = false;
				}
				fclose($this->smtp_sock);
				continue;
			}
			$this->log_write("Disconnected from remote host\n");
			$this->log_write("Error: Cannot send email to ".$rcpt_to."\n");
			$sent = false;
		}
		return $sent;
	}
	
	private function smtp_send($from, $mailto, $header, $body = ''){
		if(!$this->validate($mailto)) return false;
		
		if (!$this->smtp_putcmd('HELO', $this->smtp_helo)) {
			return $this->smtp_error('sending HELO command');
		}
		# auth login
		if($this->smtp_auth){
			if (!$this->smtp_putcmd('AUTH LOGIN', base64_encode($this->smtp_user))) {
				return $this->smtp_error('sending HELO command');
			}
	
			if (!$this->smtp_putcmd('', base64_encode($this->smtp_pass))) {
				return $this->smtp_error('sending HELO command');
			}
		}
		# send mail
		if (!$this->smtp_putcmd('MAIL', "FROM:<$from>")) {
			return $this->smtp_error('sending MAIL FROM command');
		}
		
		if (!$this->smtp_putcmd('RCPT', "TO:<$mailto>")) {
			return $this->smtp_error('sending RCPT TO command');
		}
		
		if (!$this->smtp_putcmd('DATA')) {
			return $this->smtp_error('sending DATA command');
		}
		
		if (!$this->smtp_putdata($header, $body)) {
			return $this->smtp_error('sending message');
		}
		
		if (!$this->smtp_puteom()) {
			return $this->smtp_error('sending <CR><LF>.<CR><LF> [EOM]');
		}
		
		if (!$this->smtp_putcmd('QUIT')) {
			return $this->smtp_error('sending QUIT command');
		}
		
		return true;
	}
	
	private function smtp_open($address) {
		if ($this->smtp_host == '') {
			if(!$this->validate($address)) return false;
			return $this->smtp_open_mx($address);
		} else {
			return $this->smtp_open_relay();
		}
	}
	
	private function smtp_open_relay() {
		$this->log_write("Trying to {$this->smtp_host}:{$this->smtp_port}\n");
		$this->smtp_sock = @fsockopen($this->smtp_host, $this->smtp_port, $errno, $errer, $this->time_out);
		if ($this->smtp_sock && $this->smtp_getok()) {
			$this->log_write("Connected to relay host {$this->smtp_host}\n");
			return true;
		}
		$this->log_write("Error: Cannot connenct to relay host {$this->smtp_host}\n");
		$this->log_write("Error: $errer ($errno)\n");
		return false;
	}
	
	private function smtp_open_mx($address) {
		$domain = preg_replace('/^.+@([^@]+)$/is', '\1', $address);
		if (!@getmxrr($domain, $mxhosts)) {
			$this->log_write("Error: Cannot resolve MX \"".$domain."\"\n");
			return false;
		}
		foreach ($mxhosts as $mxhost) {
			$this->log_write("Trying to $mxhost:{$this->smtp_port}\n");
			$this->smtp_sock = @fsockopen($mxhost, $this->smtp_port, $errno, $errer, $this->time_out);
			if ($this->sock && $this->smtp_getok()) {
				$this->log_write("Connected to mx host $mxhost\n");
				return true;
			
			}
			$this->log_write("Warning: Cannot connect to mx host $mxhost\n");
			$this->log_write("Error: $error ($errno)\n");
			continue;
		}
		$this->log_write("Error: Cannot connect to any mx hosts (".implode(', ', $mxhosts).")\n");
		return false;
	}
	
	private function smtp_putcmd($cmd, $arg = '') {
		if ($arg != '') {
			if($cmd == '') $cmd = $arg;
			else $cmd = "$cmd $arg";
		}
		
		fputs($this->smtp_sock, "$cmd\r\n");
		$this->smtp_debug("> $cmd\n");
		
		return $this->smtp_getok();
	}
	
	private function smtp_putdata($header, $body) {
		fputs($this->smtp_sock, $header."\r\n".$body);
		$this->smtp_debug('> '.str_replace("\r\n", "\n> ", $header."\n> ".$body."\n> "));	
		return true;
	}
	
	private function smtp_puteom() {
		fputs($this->smtp_sock, "\r\n.\r\n");
		$this->smtp_debug("[EOM]\n");
		return $this->smtp_getok();
	}
	
	private function smtp_getok() {
		$response = str_replace("\r\n", '', fgets($this->smtp_sock, 512));
		$this->smtp_debug("$response\n");
		
		if (!preg_match('/^[23]/', $response)) {
			fputs($this->smtp_sock, "QUIT\r\n");
			fgets($this->smtp_sock, 512);
			$this->log_write("Error: Remote host returned \"$response\"\n");
			return false;
		}
		return true;
	}
		
	private function smtp_debug($message){
		if($this->debug) echo '<br>'.htmlspecialchars($message);
	}
	
	private function smtp_error($message) {
		$this->log_write("Error: Error occurred while $message\n");
		return false;
	}
	
	private function get_address($address){
		$address = preg_replace('/\([^()]*\)/is', '', $address);
		$address = preg_replace('/([ \t\r\n])+/is', '', $address);
		$address = preg_replace('/^.*<(.+)>.*$/is', '\1', $address);
		return $address;
	}
	
	private function log_write($message){
		$this->smtp_debug($message);
		if ($this->logfile == '') return true;
		
		if ($fp = @fopen($this->logfile, 'a')) {
			flock($fp, LOCK_EX);
			fputs($fp, date('[Y-m-d H:i:s] ').get_current_user().'['.getmypid().']: '.$message);
			fclose($fp);
			return true;
		}
		
		$this->smtp_debug("Warning: Cannot open log file {$this->logfile}\n");
		return false;
	}
}
?>